import json
import hashlib
import os
from datetime import datetime, timedelta

ADDONS = [
    "HEXX86", "HEXX64", "HEXARM", "HEXARM64", "HEXMIPS", "HEXMIPS64",
    "HEXPPC", "HEXPPC64", "HEXRV64", "HEXARC", "HEXARC64"
]
LICENSE_FILENAME = "idapro.hexlic"
MAX_YEARS = 10

pub_modulus_patched = int.from_bytes(
    bytes.fromhex(
        "EDFD42CBF978546E8911225884436C57140525650BCF6EBFE80EDBC5FB1DE68F4C66C29CB22EB668788AFCB0ABBB718044584B810F8970CDD"
        "F227385F75D5DDDD91D4F18937A08AA83B28C49D12DC92E7505BB38809E91BD0FBD2F2E6AB1D2E33C0C55D5BDDD478EE8BF845FCEF3C82B9D"
        "2929ECB71F4D1B3DB96E3A8E7AAF93"
    ),
    "little"
)
private_key = int.from_bytes(
    bytes.fromhex(
        "77C86ABBB7F3BB134436797B68FF47BEB1A5457816608DBFB72641814DD464DD640D711D5732D3017A1C4E63D835822F00A4EAB619A2C4791"
        "CF33F9F57F9C2AE4D9EED9981E79AC9B8F8A411F68F25B9F0C05D04D11E22A3A0D8D4672B56A61F1532282FF4E4E74759E832B70E98B9D102"
        "D07E9FB9BA8D15810B144970029874"
    ),
    "little"
)

def banners():
    print("""
██╗   ██╗██╗  ██╗██╗   ██╗     ██╗██╗███╗   ██╗    ██╗  ██╗███████╗██╗  ██╗██╗     ██╗ ██████╗
╚██╗ ██╔╝██║  ██║██║   ██║     ██║██║████╗  ██║    ██║  ██║██╔════╝╚██╗██╔╝██║     ██║██╔════╝
 ╚████╔╝ ███████║██║   ██║     ██║██║██╔██╗ ██║    ███████║█████╗   ╚███╔╝ ██║     ██║██║     
  ╚██╔╝  ██╔══██║██║   ██║██   ██║██║██║╚██╗██║    ██╔══██║██╔══╝   ██╔██╗ ██║     ██║██║     
   ██║   ██║  ██║╚██████╔╝╚█████╔╝██║██║ ╚████║    ██║  ██║███████╗██╔╝ ██╗███████╗██║╚██████╗
   ╚═╝   ╚═╝  ╚═╝ ╚═════╝  ╚════╝ ╚═╝╚═╝  ╚═══╝    ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚══════╝╚═╝ ╚═════╝
                                                                                              
 ██████╗ ███████╗███╗   ██╗███████╗██████╗  █████╗ ████████╗ ██████╗ ██████╗                  
██╔════╝ ██╔════╝████╗  ██║██╔════╝██╔══██╗██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗                 
██║  ███╗█████╗  ██╔██╗ ██║█████╗  ██████╔╝███████║   ██║   ██║   ██║██████╔╝                 
██║   ██║██╔══╝  ██║╚██╗██║██╔══╝  ██╔══██╗██╔══██║   ██║   ██║   ██║██╔══██╗                 
╚██████╔╝███████╗██║ ╚████║███████╗██║  ██║██║  ██║   ██║   ╚██████╔╝██║  ██║                 
 ╚═════╝ ╚══════╝╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝   ╚═╝    ╚═════╝ ╚═╝  ╚═╝                 
    """)

def create_license_data(name, email, years):
    start_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    end_date = (datetime.now() + timedelta(days=365 * years)).strftime("%Y-%m-%d %H:%M:%S")
    
    return {
        "header": {"version": 1},
        "payload": {
            "name": name,
            "email": email,
            "licenses": [
                {
                    "id": "48-2137-ACAB-99",
                    "edition_id": "ida-pro",
                    "description": "license",
                    "license_type": "named",
                    "product": "IDA",
                    "product_id": "IDAPRO",
                    "product_version": "9.1",
                    "seats": 1,
                    "start_date": start_date,
                    "end_date": end_date,
                    "issued_on": start_date,
                    "owner": "HexRays",
                    "add_ons": [],
                    "features": [],
                }
            ],
        },
    }

def add_all_addons(license_dict):
    start_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    end_date = (datetime.now() + timedelta(days=365 * MAX_YEARS)).strftime("%Y-%m-%d %H:%M:%S")
    
    base = license_dict["payload"]["licenses"][0]
    for idx, code in enumerate(ADDONS, start=1):
        base["add_ons"].append({
            "id": f"48-1337-0000-{idx:02}",
            "code": code,
            "owner": base["id"],
            "start_date": start_date,
            "end_date": end_date,
        })

def json_stringify_sorted(obj):
    return json.dumps(obj, sort_keys=True, separators=(",", ":"))

def int_to_le_bytes(i: int) -> bytes:
    return i.to_bytes((i.bit_length() + 7) // 8, "little")

def le_bytes_to_int(b: bytes) -> int:
    return int.from_bytes(b, "little")

def encrypt(data: bytes) -> bytes:
    encrypted = pow(le_bytes_to_int(data[::-1]), private_key, pub_modulus_patched)
    return int_to_le_bytes(encrypted)

def sign_license(payload: dict) -> str:
    data_str = json_stringify_sorted({"payload": payload})
    buffer = bytearray(128)
    buffer[:33] = b"\x42" * 33
    digest = hashlib.sha256(data_str.encode()).digest()
    buffer[33:65] = digest
    encrypted = encrypt(buffer)
    return encrypted.hex().upper()

def generate_license_file(name, email, years):
    script_dir = os.path.dirname(os.path.abspath(__file__))
    output_path = os.path.join(script_dir, LICENSE_FILENAME)
    
    license_data = create_license_data(name, email, years)
    add_all_addons(license_data)
    license_data["signature"] = sign_license(license_data["payload"])
    
    with open(output_path, "w") as f:
        f.write(json_stringify_sorted(license_data))
    
    return output_path

if __name__ == "__main__":
    banners()
    
    name = input("Enter name: ").strip()
    email = input("Enter email: ").strip()
    
    while True:
        try:
            years = int(input(f"Enter duration (1-{MAX_YEARS} years): ").strip())
            if 1 <= years <= MAX_YEARS:
                break
            print(f"Please enter between 1 and {MAX_YEARS}")
        except ValueError:
            print("Please enter a valid number")
    
    print(f"\nGenerating license for:")
    print(f"  Name: {name}")
    print(f"  Email: {email}")
    print(f"  Duration: {years} year(s)")
    print(f"  Expires: {(datetime.now() + timedelta(days=365 * years)).strftime('%Y-%m-%d')}")
    
    output_path = generate_license_file(name, email, years)
    print(f"\nLicense saved to: {output_path}")